package iiris

import (
	"context"
	"fmt"
	"gitee.com/tietang/terrace-go/v2/base"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/core/router"
	"github.com/kataras/iris/v12/middleware/logger"
	"github.com/kataras/iris/v12/middleware/recover"
	"github.com/kataras/pio"
	log "github.com/sirupsen/logrus"
	"github.com/tietang/props/v3/kvs"
	"os"
	"strings"
	"time"
)

//iris 应用程序管理器

var irisApplication *iris.Application

//全局暴露
func Iris() *iris.Application {
	base.Check(irisApplication)
	return irisApplication
}

func initIris(conf kvs.ConfigSource, errorHandler iris.Handler) *iris.Application {
	app := iris.New()
	app.Use(recover.New())
	cfg := logger.Config{
		// Status displays status code
		Status: true,
		// IP displays request's remote address
		IP: true,
		// Method displays the http method
		Method: true,
		// Path displays the request path
		Path: true,
		// Query appends the url query to the Path.
		Query: true,

		// if !empty then its contents derives from `ctx.Values().Get("logger_message")
		// will be added to the logs.
		MessageContextKeys: []string{"logger_message"},

		// if !empty then its contents derives from `ctx.GetHeader("User-Agent")
		MessageHeaderKeys: []string{"User-Agent"},
		LogFunc: func(now time.Time, latency time.Duration, status, ip, method, path string, message interface{}, headerMessage interface{}) {
			app.Logger().Infof("| %s | %s | %s | %s | %s | %s | %s ",
				now.Format("2006-01-02.15:04:05.000000"), latency.String(), status, ip, method, path, headerMessage)
		},
	}

	app.Use(logger.New(cfg))
	if conf.GetBoolDefault("iris.debug", false) {
		app.Logger().SetLevel("debug")
	}
	config := iris.Configuration{}
	err := kvs.Unmarshal(conf, &config, "iris")
	if err != nil {
		panic(err)
	}
	app.Configure(iris.WithConfiguration(config))
	//app.OnErrorCode(http.StatusNotFound, func(i context.Context) {
	//
	//})
	//app.OnAnyErrorCode(func(i context.Context) {
	//	log.Warn("err: ", i.Path())
	//})
	//app.OnAnyErrorCode(func(ctx context.Context) {
	//
	//
	//})
	resetIrisGologLevel()
	logger := app.Logger()
	//扩展golog日志外部Logge实现，这里扩展为logrus
	//logger.Install(log.StandardLogger())
	//初始化时启用debug以方便查看注册信息
	//logger.SetLevel("debug")
	timeFormat := conf.GetDefault("log.timeFormat", base.TIME_FORMAT_FULL_6)
	logger.TimeFormat = timeFormat
	printer := pio.NewPrinter("", os.Stdout)
	printer.EnableDirectOutput()
	gh := NewGologHijacker()
	if conf.GetBoolDefault("log.enableLineLog", true) {
		gh.EnableFileNameLog = true
		gh.EnableFuncNameLog = true
	} else {
		gh.EnableFileNameLog = false
		gh.EnableFuncNameLog = false
	}

	if conf.GetBoolDefault("log.enableShortName", true) {
		gh.EnableShortFuncName = true
	} else {
		gh.EnableShortFuncName = false
	}

	printer.Hijack(gh.Fire)
	logger.Printer = printer

	irisApplication = app
	//app.OnAnyErrorCode(func(context iris.Context) {
	//	m := context.Method()
	//	log.Error(m, context.Domain())
	//})
	if errorHandler == nil {

		app.OnAnyErrorCode(func(ctx iris.Context) {
			ctx.JSON(iris.Map{
				"status":  ctx.GetStatusCode(),
				"method":  ctx.Method(),
				"domain":  ctx.Domain(),
				"code":    ctx.Values().GetStringDefault("code", ""),
				"message": ctx.Values().GetStringDefault("message", ""),
				"trace":   ctx.Values().GetStringDefault("trace", "")})
		})
	} else {
		app.OnAnyErrorCode(errorHandler)
	}
	return app
}

type IrisServerStarter struct {
	base.BaseStarter
	addr         string
	ErrorHandler iris.Handler
}

func (s *IrisServerStarter) Init(ctx base.StarterContext) {
	initIris(ctx.Props(), s.ErrorHandler)
	conf := ctx.Props()
	ctxPath := conf.KeyValue("application.context.path")
	contextPath := ctxPath.Value()
	ctx[contextPath] = contextPath
	Iris().Use(func(ctx iris.Context) {
		ctx.ViewData("contextPath", ctxPath.Value())
		ctx.Next()
	})
}
func (s *IrisServerStarter) Setup(ctx base.StarterContext) {}
func (s *IrisServerStarter) Start(ctx base.StarterContext) {
	for _, r := range Iris().GetRoutes() {
		if r.StatusCode > 0 {
			continue
		}
		//names := r.MainHandlerName + ": "
		//for _, h := range r.Handlers {
		//	names += ", " + irisctx.HandlerName(h)
		//}
		log.Infof("%s %s %s %s ", r.GetTitle(), r.Path, r.MainHandlerName, r.Subdomain)
	}

	//和logrus日志级别保持一致
	Iris().Logger().SetLevel(ctx.Props().GetDefault("log.level", "info"))
	port := ctx.Props().GetDefault("app.server.port", "8080")
	addr := ":" + port
	outAddr := "0.0.0.0:" + port
	log.Info("Iris listening on: ", outAddr)
	s.addr = outAddr
	idleConnsClosed := make(chan struct{})
	iris.RegisterOnInterrupt(func() {
		timeout := 10 * time.Second
		ctx, cancel := context.WithTimeout(context.Background(), timeout)
		defer cancel()
		// close all hosts.
		Iris().Shutdown(ctx)
		close(idleConnsClosed)
	})

	//Iris().Run(iris.Addr(addr), iris.WithoutInterruptHandler, iris.WithoutServerError(iris.ErrServerClosed))

	Iris().Listen(addr, iris.WithoutInterruptHandler, iris.WithoutServerError(iris.ErrServerClosed))
}

func (s *IrisServerStarter) StartBlocking() bool { return true }
func (s *IrisServerStarter) Stop(ctx base.StarterContext) {
	contx, _ := context.WithTimeout(context.Background(), 20*time.Second)
	Iris().Shutdown(contx)
	log.Info("Shutdown iris server port on：", s.addr)
}

type BaseIrisApi struct {
	GroupRouter iris.Party
}

func Trace(r *router.Route) string {
	printfmt := fmt.Sprintf("[%s:%d] %s:", r.SourceFileName, r.SourceLineNumber, r.Method)
	if r.Subdomain != "" {
		printfmt += fmt.Sprintf(" %s", r.Subdomain)
	}
	printfmt += fmt.Sprintf(" %s ", r.Tmpl().Src)

	mainHandlerName := r.MainHandlerName
	if !strings.HasSuffix(mainHandlerName, ")") {
		mainHandlerName += "()"
	}
	if l := r.RegisteredHandlersLen(); l > 1 {
		printfmt += fmt.Sprintf("-> %s and %d more", mainHandlerName, l-1)
	} else {
		printfmt += fmt.Sprintf("-> %s", mainHandlerName)
	}

	// printfmt := fmt.Sprintf("%s: %s >> %s", r.Method, r.Subdomain+r.Tmpl().Src, r.MainHandlerName)
	// if l := len(r.Handlers); l > 0 {
	// 	printfmt += fmt.Sprintf(" and %d more", l)
	// }
	return printfmt // without new line.
}
